#!/usr/bin/env python
#!coding:utf-8

import time,math
from Queue import deque
from thor.common import config

'''
Created on jun 8, 2012

@author: shankj

由失效检测的经典论文The Phi accrual failure detector 
（http://vsedach.googlepages.com/HDY04.pdf）中的证明，分布式环境中,对主机的心跳统计,
根据以往心跳间隔的经验值,可以由下面的方法判断主机是否宕机。

1. 给定一个阀值 Φ

2. 在一定时间内,记录各个心跳间隔时间

3. 对心跳的间隔值求指数分布(Exponential distribution)概率:

P = E ^ (-1 * (now - lastTimeStamp) / mean) （E是对数2.71828...，mean为此前的间隔时间平均值）

其表示,自上次统计以来,心跳到达时间将超过 now - lastTimeStamp 的概率

4. 计算 φ = - log10 P

5. 当φ > Φ 时，就可以认为主机已经宕机了。

当然这可能会存在误判，误判的可能性如下：

Φ = 1, 1%

Φ = 2, 0.1%

Φ = 3, 0.01%

......

Φ = 8, 0.0000001%

由此可见，当Φ = 8时，误判率已经很小了。默认采用Φ = 8。'''

SAMPLE_WINDOW_SIZE = 1000
conf = config.load_settings("schedule")

class faile_detector(object):
	def __init__(self):
		self.lastTimeStamp = 0
		self.samples = deque(maxlen=SAMPLE_WINDOW_SIZE)
		self.detect_value = conf.get_int('phi.failrue.detect')
		assert self.detect_value

	def now(self):
		"we need microsecord"
		return time.time()*1000

	def add_sample(self):
		"增加采样"
		now = self.now()

		if self.lastTimeStamp > 0:
			t = now-self.lastTimeStamp
		else:
			t = 1000/2

		self.lastTimeStamp = now
		
		self.samples.append(t) #如果达到上限则移除最早的(deque)

	def phi(self):
		avag = sum(self.samples)/len(self.samples)

		#P = E ^ (-1 * (now - lastTimeStamp) / mean) 
		p = math.pow(math.e,((-1)*(self.now() - self.lastTimeStamp)/avag))
		if p:
			return math.log10(p) * (-1)


	def service_up(self):
		return self.phi() < self.detect_value


if __name__ == '__main__':
	d = faile_detector()
	for i in range(1010):
		d.add_sample()
		time.sleep(0.01)

	print d.service_up() #up

	time.sleep(0.5)

	for i in range(1010):
		d.add_sample()
		time.sleep(0.01)

	time.sleep(1.5)  #here is fail time

	print d.service_up() #down